/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. All rights reserved.
 * secPaver is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package service

import (
	"context"
	"fmt"
	pbEngine "gitee.com/openeuler/secpaver/api/proto/engine"
	"gitee.com/openeuler/secpaver/common/log"
	"gitee.com/openeuler/secpaver/engine"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/emptypb"
	"sync"
)

// EngineService is the implement of EngineMgr service
type EngineService struct {
	sync.Mutex

	engines map[string]engine.Engine

	Name string
	pbEngine.UnimplementedEngineMgrServer
}

// NewEngineService is the constructor of EngineService
func NewEngineService(engines map[string]engine.Engine) (*EngineService, error) {
	return &EngineService{
		Name:    "engine",
		engines: engines,
	}, nil
}

// ServiceName returns the name of service
func (s *EngineService) ServiceName() string {
	return s.Name
}

// RegisterServer registers service in the grpc server
func (s *EngineService) RegisterServer(server *grpc.Server) error {
	pbEngine.RegisterEngineMgrServer(server, s)
	return nil
}

// ListEngine is the remote implement of the ListEngine rpc
func (s *EngineService) ListEngine(_ context.Context, _ *emptypb.Empty) (*pbEngine.ListAck, error) {
	s.Lock()
	defer s.Unlock()

	log.Infof("rpc request: ListEngine")

	ack := &pbEngine.ListAck{}
	for _, eng := range s.engines {
		if eng == nil {
			continue
		}

		ack.List = append(ack.List, &pbEngine.ListAck_Engine{
			Name: eng.GetName(),
			Desc: eng.GetDescription(),
		})
	}

	return ack, nil
}

// InfoEngine is the remote implement of the InfoEngine rpc
func (s *EngineService) InfoEngine(_ context.Context, req *pbEngine.Req) (*pbEngine.InfoAck, error) {
	s.Lock()
	defer s.Unlock()

	if err := req.ValidateAll(); err != nil {
		return &pbEngine.InfoAck{}, err
	}

	log.Infof("rpc request: InfoEngine, name: %s", req.GetEngine())

	eng, ok := s.engines[req.GetEngine()]
	if !ok || eng == nil {
		return &pbEngine.InfoAck{}, fmt.Errorf("invalid engine %s", req.GetEngine())
	}

	return &pbEngine.InfoAck{
		Info: &pbEngine.InfoAck_Engine{
			Name: eng.GetName(),
			Desc: eng.GetDescription(),
		},
	}, nil
}
